/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sirtet;

import sirtet.event.PlayerActionEvent;
import sirtet.event.PlayerEvent;
import sirtet.event.PlayerListener;

/**
 * This player limits the frequency of invocations of actions by rejecting all
 * actions invoked too closely to the previous one.
 * @author guangwei.zhu
 */
public class ControlledPlayer extends Player {

    private Player controlledPlayer;
    // private boolean allowSignal;
    // private CongestionControlThread controlThread;
    private long interval;
    private long lastMilli;
    // private final Object lock = new Object();
    private PlayerListener listener = new PlayerListener() {
        // This listener serves as a delegate

        public void actionPerformed(PlayerActionEvent evt) {
            /*
            synchronized (lock) {
                if (!getEnabled()) {
                    return; // Disabled state
                }
                if (!allowSignal) {
                    return;
                }
                allowSignal = false;
                lock.notifyAll();
            }
             * */
            if (!getEnabled()) {
                return;
            }
           if (System.currentTimeMillis() - lastMilli <= interval) {
                return;
            }
            lastMilli = System.currentTimeMillis();
            invokeAction(evt.action);
            /*
            while (true) {
                synchronized (lock) {
                    if (allowSignal) {
                        break;
                    }
                }
                Thread.yield();
            }
            synchronized (lock) {
                allowSignal = false;
            }*/
        }

        public void playerQuit(PlayerEvent evt) {
            quit();
        }

        public void playerEnabled(PlayerEvent evt) {
            setEnabled(true);
        }

        public void playerDisabled(PlayerEvent evt) {
            setEnabled(false);
        }

        public void playerReady(PlayerEvent evt) {
            setReady(true);
        }
    };

    @Override
    public void bindBoard(GameBoard board) {
        super.bindBoard(board);
        controlledPlayer.bindBoard(board);
    }

    @Override
    public void unbindBoard(GameBoard board) {
        super.unbindBoard(board);
        controlledPlayer.unbindBoard(board);
    }

    /*
    private class CongestionControlThread extends Thread {

        @Override
        public void run() {
            while (true) {
                try {
                    synchronized (lock) {
                        lock.wait(interval);
                    }
                } catch (Exception e) {
                }
                allowSignal = true;
            }
        }
    }
     * */

    /**
     * Wrap an original Player object to enforce a minimum action interval on
     * that player.
     * @param innerPlayer the Player who is to be controlled
     * @param interval the minimum action interval allowed
     */
    public ControlledPlayer(Player innerPlayer, int interval) {
        super(innerPlayer);
        this.controlledPlayer = innerPlayer;
        setInterval(interval);
        innerPlayer.addPlayerListener(listener);    // Hook on the delegate
        // allowSignal = true;
        lastMilli = System.currentTimeMillis();
    }

    public void setInterval(int interval) {
        this.interval = interval;
    }

    @Override
    public void setEnabled(boolean enabled) {
        boolean oldEnabled = this.getEnabled();
        super.setEnabled(enabled);
        this.controlledPlayer.setEnabled(enabled);
        /*
        if (oldEnabled != enabled) {
            try {
                synchronized (lock) {
                    if (enabled) {
                        allowSignal = true;
                        controlThread = new CongestionControlThread();
                        controlThread.start();
                    } else {
                        controlThread.interrupt();
                        controlThread = null;
                    }
                }
            } catch (Exception ex) {
            }
        }
         * */
    }
}
